package me.itsoo.artemis.framework.ioc.context;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import me.itsoo.artemis.framework.core.ResourceScanner;
import me.itsoo.artemis.framework.core.env.Environment;
import me.itsoo.artemis.framework.core.util.AnnotationUtils;
import me.itsoo.artemis.framework.core.util.StringUtils;
import me.itsoo.artemis.framework.ioc.bean.BeanDefinition;
import me.itsoo.artemis.framework.ioc.bean.BeanMatchPatterns;
import me.itsoo.artemis.framework.ioc.factory.DefaultBeanFactory;
import me.itsoo.artemis.framework.ioc.lang.Matches;
import me.itsoo.artemis.framework.ioc.util.BeanUtils;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * DefaultApplicationContext
 *
 * @author zxy
 * @version 0.0.1
 * @since 2023/6/2
 */
@Slf4j
public class DefaultApplicationContext extends AbstractApplicationContext {

    @Getter
    private final Environment environment;

    @Getter
    private final ResourceScanner resourceScanner;

    @Getter
    private final DefaultBeanFactory beanFactory;

    @Setter
    private String name;

    protected BeanMatchPatterns pattern = new BeanMatchPatterns();

    public DefaultApplicationContext(String applicationConfig, String scanBasePackage) {
        this.environment = Environment.createAppProperties(applicationConfig);
        this.resourceScanner = new ResourceScanner(scanBasePackage);
        this.beanFactory = new DefaultBeanFactory();

        this.name = "ApplicationContext#" + applicationConfig;
    }

    @Override
    public Class<?>[] getClasses() {
        return resourceScanner.getClasses();
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void refresh() {
        registryBeanDefinitions();

        registryBeans();

        // TODO: 发布事件
    }

    @Override
    public String[] getAllBeanNames() {
        return beanFactory.getAllBeanNames();
    }

    /**
     * 注册 BeanDefinition
     */
    private void registryBeanDefinitions() {
        for (Class<?> beanClass : getClasses()) {
            final String beanName = BeanUtils.getBeanName(beanClass);

            if (isMatchedBeanClass(beanName, beanClass)) {
                beanFactory.registerBeanDefinition(beanName, beanClass);
            }
        }
    }

    /**
     * 注册 Bean
     */
    private void registryBeans() {
        final Set<String> uniqueBeanNameSet = new HashSet<>();
        for (BeanDefinition bd : beanFactory.getAllBeanDefinitions()) {
            final String beanName = bd.getBeanName();
            if (uniqueBeanNameSet.add(beanName)) {
                beanFactory.getBean(beanName);
            }
        }
    }

    /**
     * 是否为符合要求的 Bean
     *
     * @param beanName  String
     * @param beanClass Class
     * @return boolean
     */
    private boolean isMatchedBeanClass(String beanName, Class<?> beanClass) {
        final Matches ann = AnnotationUtils.findAnnotation(beanClass, Matches.class);
        if (Objects.nonNull(ann) && StringUtils.isNotBlank(ann.value())) {
            return pattern.match(ann.value(), beanName);
        }

        return true;
    }
}
